﻿using SimpleTerminal.Library;
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Win32;

namespace SimpleTerminal.Controls
{
    public partial class TabLayout : Control
    {
        private readonly ArrayList Labels = new ArrayList();
        public readonly ArrayList Items = new ArrayList();
        private int selecedIndex = -1;


        public EventHandler<TabEventArgs> TabClosing;
        public EventHandler<TabEventArgs> TabClosed;
        public EventHandler<TabEventArgs> TabCreated;
        public EventHandler<TabEventArgs> TabBarClick;
        public EventHandler<TabEventArgs> TabToOther;
        public EventHandler<TabEventArgs> SelectChanged;
        public EventHandler Actived;
        public bool actived;

        //Panel separator;
        Panel tabContainer;
        Panel shownContainer;
        Panel tabBar;
        Label tabList;

        private int tabHeight = 28;
        private int tabPaddingLeft = 5;
        Point point;


        private Color tabsBarBackgroundColor = SystemColors.Control;

        [Category("自定义属性")]
        [Description("标签栏的背景色")]
        public Color TabBarBackgroundColor
        {
            get { return tabsBarBackgroundColor; }
            set
            {
                tabsBarBackgroundColor = value;
                if (tabBar != null)
                    tabBar.BackColor = value;
            }
        }
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (m.Msg == 0x21 && !actived)
            {
                actived = true;
                Actived?.Invoke(this, EventArgs.Empty);
                if (selecedIndex > -1 && selecedIndex < Items.Count)
                {
                    ((PageContainer)Items[selecedIndex]).Select();
                }
            }
        }
        public bool Active
        {
            set
            {
                actived = value;
            }
        }

        /*
        protected virtual void RenderItem(Graphics graphics, Rectangle rectangle, PageContainer pageContainer)
        {
            SolidBrush bgBbrush = new SolidBrush(BackColor);
            graphics.FillRectangle(bgBbrush, rectangle);

            SizeF sizeF = graphics.MeasureString(pageContainer.Text, Font);

            graphics.DrawString(pageContainer.Text, Font, new SolidBrush(ForeColor),
                  rectangle.X + 8,
                 (labelHeight - sizeF.Height) / 2
                  );
        }
        */
        class LabelComponent
        {
            Rectangle rectangle;
            bool selected;
            bool hover;
            Color textColor;
            Color selectdBgColor;
            Color selectdTextColor;
            Color backgroundColor;
            Color hoverColor;
            string text;
            Font font;
            int labelHeight;

            public Rectangle Rectangle { get => rectangle; set => rectangle = value; }
            public bool Selected { get => selected; set => selected = value; }
            public Color SelectdBgColor { get => selectdBgColor; set => selectdBgColor = value; }
            public Color SelectdTextColor { get => selectdTextColor; set => selectdTextColor = value; }
            public Color HoverColor { get => hoverColor; set => hoverColor = value; }
            public Color BackgroundColor { get => backgroundColor; set => backgroundColor = value; }
            public int LabelHeight { get => labelHeight; set => labelHeight = value; }

            private void OnPaint(Graphics graphics, Rectangle rectangle)
            {
                Color bg = selected ? selectdBgColor : (hover ? hoverColor : backgroundColor);
                Color tc = selected ? selectdTextColor : (hover ? selectdTextColor : textColor);
                font = new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(134)));

                SizeF sizeF = graphics.MeasureString(text, font);
                SolidBrush solidBrush = new SolidBrush(tc);
                SolidBrush bgBbrush = new SolidBrush(backgroundColor);

                graphics.FillRectangle(bgBbrush, rectangle);
                graphics.DrawString(text, font, new SolidBrush(tc),
                      rectangle.X + 8,
                     (labelHeight - sizeF.Height) / 2
                      );
            }
        }

        class ShownContainer : Panel
        {
            public new CreateParams CreateParams
            {
                get
                {
                    CreateParams cp = base.CreateParams;
                    cp.Style |= User32.WS_CLIPCHILDREN;
                    return cp;
                }
            }

        }

        public TabLayout()
        {
            InitializeComponent();
            SuspendLayout();
            tabBar = new Panel();
            tabContainer = new Panel();
            shownContainer = new ShownContainer();
            tabList = new Label();

            tabBar.Margin = new Padding(0);
            tabBar.Padding = new Padding(0, 0, 0, 0);
            tabBar.Location = new Point(0, 0);
            tabBar.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
            tabBar.Size = new Size(Width, TabHeight);
            tabBar.BackColor = tabsBarBackgroundColor;
            //tabBar.BackColor = Color.FromArgb(40, 43, 61);
            tabBar.Resize += TabContainer_OnResize;

            tabContainer.Margin = new Padding(0);
            tabContainer.Padding = new Padding(0);
            tabContainer.Location = new Point(tabPaddingLeft, 0);
            tabContainer.Anchor = AnchorStyles.Top | AnchorStyles.Left |
                AnchorStyles.Right | AnchorStyles.Bottom;
            tabContainer.Size = new Size(tabBar.Width - 31 - tabPaddingLeft, TabHeight);
            ///tabContainer.BackColor = Color.Transparent;
            tabContainer.Resize += TabContainer_OnResize;

            tabList.Margin = new Padding(0);
            tabList.Padding = new Padding(5);
            tabList.Location = new Point(tabBar.Width - 26, (TabHeight - 21) / 2);
            tabList.Size = new Size(21, 21);
            tabList.Anchor = AnchorStyles.Top | AnchorStyles.Right;
            tabList.AutoSize = false;
            tabList.BackColor = Color.Transparent;
            tabList.BackgroundImageLayout = ImageLayout.Stretch;
            tabList.BackgroundImage = Properties.Resources.tablist;
            tabList.FlatStyle = FlatStyle.Flat;
            tabList.Text = "";
            tabList.Click += TabList_OnClick;
            tabList.MouseEnter += TabList_MouseEnter;
            tabList.MouseLeave += TabList_MouseLeave;

            tabListAll.Renderer = new Render.ToolStripSimpleRender();

            tabBar.SuspendLayout();

            tabBar.Controls.Add(tabContainer);
            tabBar.Controls.Add(tabList);

            tabBar.ResumeLayout(false);

            shownContainer.Size = new Size(Width, Height - tabBar.Height);
            shownContainer.Anchor = AnchorStyles.Top | AnchorStyles.Left |
                AnchorStyles.Right | AnchorStyles.Bottom;
            shownContainer.Location = new Point(0, tabBar.Height);
            shownContainer.ImeMode = ImeMode.NoControl;
            shownContainer.Margin = new Padding(0);


            Controls.Add(tabBar);
            Controls.Add(shownContainer);
            point = new Point(0, 0);
            ResumeLayout(false);
        }

        protected override bool ProcessDialogKey(Keys keyData)
        {
            return base.ProcessDialogKey(keyData);
        }



        public class TabEventArgs : EventArgs
        {
            readonly PageContainer item;

            public TabEventArgs(PageContainer item)
            {
                this.item = item;
            }

            public PageContainer Item
            {
                get
                {
                    return item;
                }
            }
        }

        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            // g = this.CreateGraphics();
        }



        public interface Listener<T>
        {
            void OnClosing(T item);
        }



        public void Remove(PageContainer item)
        {
            //listener.OnClosing(item);
            int index = Items.IndexOf(item);
            if (index == -1)
                return;
            RemoveTabPage((TabLabelControl)Labels[index], false);
        }

        private void Item_ActiveChanged(object sender, EventArgs e)
        {
            if (!(sender is PageContainer item))
                return;
            //GetTabLabelByItem(item).IndicatorActive = item.Active;
        }
        private void AddItemToControl(PageContainer item)
        {
            TabLabelControl label = new TabLabelControl();
            label.Location = new Point(point.X, point.Y);
            label.Font = new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(134)));
            label.Text = item.Text;
            label.AutoSize = false;
            label.Click += new EventHandler(OnLabelClick);
            label.Height = tabContainer.Height;
            label.MouseDown += Label_MouseDown;
            label.MouseUp += Label_MouseUp;
            label.MouseMove += Label_MouseMove;
            label.Closed += Label_Closed;
            label.ToOther += Label_ToOther;
            label.IndicatorActive = item.Indicator;
            label.BackColor = TabBarBackgroundColor;


            point.X += label.Width;

            //计算位置
            //int topOffset = tabContainer.Location.Y + tabContainer.Height;
            //item.Anchor = AnchorStyles.Top | AnchorStyles.Left |
            //     AnchorStyles.Right | AnchorStyles.Bottom;
            item.BackColor = Color.FromArgb(0, 0, 0);
            item.Location = new Point(0, 0);
            item.Visible = true;
            item.Size = shownContainer.Size;
            item.Dock = DockStyle.Fill;

            //item.Height = shownContainer.Height;
            //container.TabStop = false;
            item.ImeMode = ImeMode.NoControl;
            item.Margin = new Padding(0);
            item.TextChanged += PageContainer_TextChanged;
            item.IndicatorChanged = PageContainer_IndicatorChanged;

            tabContainer.Controls.Add(label);
            shownContainer.Controls.Add(item);



            item.TabLayout = this;


            Labels.Add(label);
            Items.Add(item);
        }

        private void PageContainer_TextChanged(object sender, EventArgs e)
        {
            //Console.WriteLine("PageContainer_TextChanged");
            int index = Items.IndexOf(sender);
            (Labels[index] as TabLabelControl).Text = (sender as PageContainer).Text;
            ReArrange();
        }

        public void AddItems(ArrayList itemArray)
        {
            SuspendLayout();
            tabContainer.SuspendLayout();
            foreach (PageContainer item in itemArray)
            {
                AddItemToControl(item);
            }
            tabContainer.ResumeLayout(false);
            ResumeLayout(false);
            SelectIndex = Items.Count - 1;

            if (Labels.Count > 0 && tabList.Visible == false)
            {
                tabList.Visible = true;
            }
        }


        public void AddItem(PageContainer item)
        {
            SuspendLayout();
            tabContainer.SuspendLayout();
            AddItemToControl(item);
            tabContainer.ResumeLayout(false);
            ResumeLayout(false);
            SelectIndex = Items.Count - 1;
            OnTabEvent(TabCreated, item);
            //PerformLayout();
            if (Labels.Count > 0 && tabList.Visible == false)
            {
                tabList.Visible = true;
            }
        }

        private int orderOffset = 0;



        public void ReArrange()
        {
            point.X = 0 - orderOffset;
            foreach (TabLabelControl tabLabel in Labels)
            {
                int width = tabLabel.Width;
                tabLabel.Location = new Point(point.X, point.Y);
                point.X += width;
            }
        }

        public void Clear()
        {
            SuspendLayout();
            tabContainer.Controls.Clear();
            shownContainer.Controls.Clear();

            Labels.Clear();
            Items.Clear();
            selecedIndex = -1;
            point.X = 0;
            tabList.Visible = false;
            ResumeLayout(false);
        }

        protected bool leftMouseKeyDown = false;


        public void Label_MouseUp(object sender, MouseEventArgs e)
        {
            leftMouseKeyDown = false;
            if (e.Button == MouseButtons.Left)
            {

            }
        }
        DelayAction delayAction = new DelayAction();
        DelayAction delayAction2 = new DelayAction();
        private void SortLabel()
        {
            SortLabel(true);
        }
        private bool SortLabel(bool flag)
        {
            TabLabelControl tabLabelControl = GetTabLabelControl(selecedIndex);
            if (tabLabelControl == null)
                return false;
            //判断标签边界
            if (tabLabelControl.Location.X + tabLabelControl.Width > tabContainer.Width)
            {
                orderOffset += tabLabelControl.Location.X + tabLabelControl.Width - tabContainer.Width;
                ReArrange();
                return true;
            }
            else if (tabLabelControl.Location.X < 0)
            {
                orderOffset -= -tabLabelControl.Location.X;
                ReArrange();
                return true;
            }
            else if (orderOffset > 0 && flag)
            {
                orderOffset -= Math.Min(tabContainer.Width - (tabLabelControl.Location.X + tabLabelControl.Width), orderOffset);
                ReArrange();
                return true;
            }

            return false;

        }
        private void PageContainer_IndicatorChanged(object sender, EventArgs e)
        {
            PageContainer pageContainer = sender as PageContainer;
            TabLabelControl tabLabelControl = (TabLabelControl)Labels[Items.IndexOf(pageContainer)];
            tabLabelControl.IndicatorActive = pageContainer.Indicator;
        }


        private void TabList_OnClick(object sender, EventArgs e)
        {

            tabListAll.Show(this, tabList.Location);
        }
        private void TabList_MouseEnter(object sender, EventArgs e)
        {
            tabList.BackColor = SystemColors.ControlLight;
        }

        private void TabList_MouseLeave(object sender, EventArgs e)
        {

            tabList.BackColor = Color.Transparent;
        }
        private void TabContainer_OnResize(object sender, EventArgs e)
        {
            base.OnResize(e);
            if (Width == 0)
                return;
            delayAction.Debounce(100, tabContainer, SortLabel);
        }

        /// <summary>
        /// 实现标签的移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Label_MouseMove(object sender, MouseEventArgs e)
        {
            if (leftMouseKeyDown)
            {
                TabLabelControl labelControl = (TabLabelControl)sender;
                int index = Labels.IndexOf(labelControl);

                TabLabelControl labelControl1 = labelControl;
                PageContainer tabGroup = Items[index] as PageContainer;

                /*
                 * 当按下鼠标左键且移动鼠标的时候则判断为试图拖拽标签
                 * 如果鼠标向右移动且移动的距离超过右侧标签的宽度 
                 * 则交换两个控件位置
                 * (e.X > 当前控件宽度 && e.X > 右侧控件宽度)
                 * 
                 * 如果鼠标向左移动且移动距离超过 当前控件宽度-左侧控件
                 * 宽度（最低0），则交换两个控件位置
                 */

                if (e.X > labelControl.Width && index + 1 <= Labels.Count - 1)
                {
                    TabLabelControl labelControl2 = (TabLabelControl)Labels[index + 1];
                    if (e.X > labelControl2.Width)
                    {
                        tabContainer.SuspendLayout();
                        // SelectIndex = index;

                        Labels[index] = labelControl2;
                        Labels[index + 1] = labelControl1;

                        Items[index] = Items[index + 1];
                        Items[index + 1] = tabGroup;

                        selecedIndex = index + 1;
                        ReArrange();
                        tabContainer.ResumeLayout(false);
                    }

                }
                else if (e.X < 0 && index - 1 >= 0)
                {
                    TabLabelControl labelControl2 = (TabLabelControl)Labels[index - 1];

                    if (e.X < Math.Min(labelControl2.Width - labelControl.Width, 0))
                    {
                        tabContainer.SuspendLayout();
                        //    SelectIndex = index;
                        Labels[index] = labelControl2;
                        Labels[index - 1] = labelControl1;

                        Items[index] = Items[index - 1];
                        Items[index - 1] = tabGroup;
                        selecedIndex = index - 1;
                        ReArrange();
                        tabContainer.ResumeLayout(false);
                    }
                }
            }
            //Log.Debug("TabLayout", "交换元素");

        }

        private void ChangeSelectIndex(int value)
        {
            User32.SendMessage(this.Handle, 11, 0, 0);
            // Application.ProcessMessages.LockWindowUpdate(0);
            if (value >= 0 && value < Items.Count)
            {
                // SuspendLayout();
                shownContainer.SuspendLayout();

                // shownContainer.
                if (selecedIndex > -1 && selecedIndex < Items.Count)
                {

                    PageContainer oldItem = Items[selecedIndex] as PageContainer;
                    TabLabelControl oldLabel = Labels[selecedIndex] as TabLabelControl;

                    oldLabel.Selected = false;
                    if (oldItem.Visible)
                        oldItem.Hide();
                }
                PageContainer item = Items[value] as PageContainer;
                TabLabelControl labelControl = Labels[value] as TabLabelControl;
                item.Dock = DockStyle.Fill;
                item.Width = shownContainer.Width;
                item.Height = shownContainer.Height;
                if (!item.Visible)
                    item.Show();
                item.Select();
                labelControl.Selected = true;

                selecedIndex = value;

                OnTabEvent(SelectChanged, item);
                shownContainer.ResumeLayout(false);
                //  ResumeLayout(false);
            }
            User32.SendMessage(this.Handle, 11, 1, 0);
            Refresh();
            //Invalidate();
        }

        /// <summary>
        /// 当前选中的Tab的索引值
        /// </summary>
        public int SelectIndex
        {
            set
            {
                ChangeSelectIndex(value);
                //判断标签边界
                SortLabel(false);
            }
            get
            {
                return selecedIndex;
            }
        }

        public int TabHeight { get => tabHeight; set => tabHeight = value; }

        public TabLabelControl GetTabLabelControl(int index)
        {
            if (index < 0 || index > Labels.Count - 1)
                return null;

            return (TabLabelControl)Labels[index];
        }

        public TabLabelControl GetTabLabelByItem(PageContainer tag)
        {
            return (TabLabelControl)Labels[Items.IndexOf(tag)];
        }


        public PageContainer Find(string name)
        {
            foreach (PageContainer pageContainer in Items)
            {
                if (pageContainer.Name.Equals(name))
                    return pageContainer;
            }
            return null;
        }

        private void Label_Closed(object sender, EventArgs e)
        {
            RemoveTabPage((TabLabelControl)sender, true);
        }
        private void Label_ToOther(object sender, EventArgs e)
        {
            int index = Labels.IndexOf(sender);
            OnTabEvent(TabToOther, (PageContainer)Items[index]);
        }
        private void OnLabelClick(object sender, EventArgs e)
        {

        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            // Console.WriteLine("OnGotFocus");

            base.OnMouseDown(e);
            //   Focus();
        }
        public void Label_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                leftMouseKeyDown = true;
                SelectIndex = Labels.IndexOf(sender);
                //Item item = Items[selecedIndex] as Item;
                //item.Control.Focus();
            }
        }
        protected override void OnGotFocus(EventArgs e)
        {
            Console.WriteLine("OnGotFocus");
            base.OnGotFocus(e);
        }

        ///获取 当前拥有焦点的控件

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);

        }

        private void OnTabEvent(EventHandler<TabEventArgs> action, PageContainer item)
        {
            action?.Invoke(this, new TabEventArgs(item));
        }

        public void RemoveTabPage(TabLabelControl tabLabelControl, bool callback)
        {
            SuspendLayout();
            tabContainer.SuspendLayout();

            int index = Labels.IndexOf(tabLabelControl);

            PageContainer item = Items[index] as PageContainer;

            //执行回调
            if (callback)
                OnTabEvent(TabClosing, item);

            //删除标签和容器
            tabContainer.Controls.Remove(tabLabelControl);
            shownContainer.Controls.Remove(item);

            //释放控件
            //tabLabelControl.Dispose();
            //item.Container.Dispose();

            //释放监听
            //item.ActiveChanged = null;
            //从数组中删除此元素
            Labels.RemoveAt(index);
            Items.RemoveAt(index);

            //如果当前标签是激活状态则切换新的选中标签
            if (index == selecedIndex && index - 1 >= 0)
            {
                ChangeSelectIndex(index - 1);
            }
            else if (index == selecedIndex && index < Items.Count)
            {
                ChangeSelectIndex(index);
            }
            else
            {
                if (selecedIndex > index)
                    selecedIndex--;
            }

            ReArrange();
            delayAction2.Debounce(800, this, delegate
            {
                SortLabel(true);
            });
            if (callback)
                OnTabEvent(TabClosed, item);
            tabContainer.ResumeLayout(false);
            ResumeLayout(false);
            if (Labels.Count == 0)
                tabList.Visible = false;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            //g = pe.Graphics;
            base.OnPaint(pe);

        }


        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
        }

        private void TabListAll_ItemClick(object sender, EventArgs e)
        {
            ToolStripMenuItem item = (ToolStripMenuItem)sender;
            int index = (int)item.Tag;
            SelectIndex = index;
        }
        private void TabListAll_Opening(object sender, CancelEventArgs e)
        {
            tabListAll.Items.Clear();

            // this.tabListAll.SuspendLayout();
            ToolStripMenuItem[] toolStripMenus = new ToolStripMenuItem[Labels.Count];
            int i = 0;
            foreach (TabLabelControl tabLabelControl in Labels)
            {
                ToolStripMenuItem item = new ToolStripMenuItem();
                item.Text = "" + (i + 1) + ". " + tabLabelControl.Text;
                item.Tag = i;
                item.DisplayStyle = ToolStripItemDisplayStyle.Text;
                item.Alignment = ToolStripItemAlignment.Left;
                item.Click += TabListAll_ItemClick;
                toolStripMenus[i] = item;
                i++;
            }
            tabListAll.Items.AddRange(toolStripMenus);
            //this.tabListAll.ResumeLayout(false);
            e.Cancel = false;
        }
    }
}
